<?php

namespace Luka\NavigationBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\DependencyInjection\ContainerInterface;

class PagenationController extends Controller {
    protected $entityManager;
    protected $perPageDefault;
    protected $perPageLeap = array(10, 25, 50, 100);
    protected $parameterBag;
    protected $locale;

    public function setContainer(ContainerInterface $container = null) {
        $this->container = $container;
        $this->init();
    }

    public function init() {
        $this->locale = $this->get('session')->getLocale();
        $this->entityManager = $this->getDoctrine()->getEntityManager();
        $request = $this->getRequest();
        $this->parameterBag = new ParameterBag(array_merge($request->query->all(), $request->request->all()));
        $this->perPageDefault = 10;
    }

    protected function page() {
        $page = $this->parameterBag->get("page")? intval($this->parameterBag->get("page")): 1;
        if($page <= 0) {
            $page = 1;
        }
        return $page;
    }

    protected function perPage() {
        if($this->parameterBag->get("per_page")) {
            $perPage = intval($this->parameterBag->get("per_page"));
        } elseif(isset($pagination["" . get_class($this)]["per_page"])) {
            $perPage = $pagination["" . get_class($this)]["per_page"];
        } else {
            $perPage = $this->perPageDefault;
        }

        if($perPage <= 0 || !in_array($perPage, $this->perPageLeap)) {
            $perPage = $this->perPageDefault;
        }

        return $perPage;
    }

    protected function orderBy($forceDefault = false, $default = "id") {
        if(!$forceDefault){
            $orderByData =  explode("-", "" . $this->parameterBag->get("order_by"));
            if($orderByData && $orderByData[0]) {
                return $orderByData[0];
            }
        }
        return $default;
    }

    protected function orderByValidation($metaData) {
        $field = $this->orderBy();
        if($metaData->hasField($field) || $metaData->hasAssociation($field)){
            return $field;
        }
        return $this->orderBy(true);
    }

    protected function orderDirection($default = "asc") {
        $orderByData =  explode("-", "" . $this->parameterBag->get("order_by"));
        $direction = $default;
        if($orderByData && isset($orderByData[1])) {
            if($orderByData[1] == "up") {
                $direction = "desc";
            } else {
                $direction = "asc";
            }
        }
        return $direction;
    }

    protected function Pagenator($repository, $alias = "a", array $fields, array $where = array(), $template = null) {
        $metaData = $this->entityManager->getClassMetadata($repository);

        $orderBy = $this->orderByValidation($metaData);

        $queryBuilder = $this->entityManager
            ->getRepository($repository)
            ->createQueryBuilder($alias)
            ->orderBy($alias.'.' . $orderBy, $this->orderDirection());

        $whereQuery = $this->WhereQueryGenerate($metaData, $alias, $where);

        if(!empty($whereQuery)){
            $queryBuilder->where($whereQuery);
        }

        $rowCount = $queryBuilder->select($queryBuilder->expr()->count($alias.".".$orderBy))->getQuery()->getSingleResult();

        $page_count = (int)ceil($rowCount[1] / $this->perPage());

        $offset = ((($this->page() > $page_count) ? $page_count : $this->page()) - 1) * $this->perPage();

        if($offset < 0){
            $offset = $this->perPage();
        }

        $query = $queryBuilder
            ->select($this->SelectQueryGenerate($alias, $fields))
            ->setFirstResult( $offset )
            ->setMaxResults( $this->perPage() )
            ->getQuery();

        return array(
            "paginator_template" => $template,
            "paginator_fields" => $fields,
            "paginator_results" => $query->getResult(),
            "paginator_current_page" => $this->page(),
            "paginator_per_page" => $this->perPage(),
            "paginator_per_page_leap" => $this->perPageLeap,
            "paginator_page_count" => $page_count,
            "paginator_order_by" => $orderBy,
            "paginator_order_direction" => $this->orderDirection()
        );
    }
    private function WhereQueryGenerate($metaData, $alias, array $where = array()) {
        $result = "";
        if(count($where) != 0){
            $queryAnd = Array();
            foreach($where as $field => $value){
                if($metaData->hasField($field) || $metaData->hasAssociation($field)){
                    $v = is_array($value) ? $value : array($value);
                    $type = $metaData->getTypeOfField($field);
                    $queryOr = Array();
                    foreach($v as $option){
                        $filter = $alias.".".$field;
                        if(empty($option)){
                            $filter .= ' is null';
                        }
                        else{
                            switch($type){
                                case 'string':
                                    $filter .= " LIKE '%".$option."%'";
                                    break;
                                case 'timestamp':
                                    $filter .= " > '" . $option ."'";
                                    break;
                                default:
                                    $filter .= " = '" . $option ."'";
                                    break;
                            }
                        }
                        $queryOr[] = $filter;
                    }
                    $queryAnd[] = "(".implode(" OR ", $queryOr).")";
                }
            }

            if(!empty($queryAnd)){
                $result = implode(" AND ", $queryAnd);
            }
        }
        return $result;
    }

    private function SelectQueryGenerate($alias, array $fields = array()) {
        if(count($fields) != 0){
            $temp = array();
            foreach($fields as $field){
                $temp[] = $alias.".".$field;
            }
            return implode(", ", $temp);
        }
        throw new \ErrorException("Pager return fields r not specified!");
    }
}